/*
 * Copyright (c) 2009. Simon Johnston. All Rights Reserved.
 */
 
grammar Sol;

options {
	language = Java;
	output = AST;
}

tokens {
	ABSTRACT= 'abstract';
	DO		= 'do';
	ELSE	= 'else';
	END 	= 'end';
	ENSURES	= 'ensures';
	EXTENDS	= 'extends';
	FEATURE = 'feature';
	FOR		= 'for';
	FUNCTION= 'function';
	IF		= 'if';
	IN		= 'in';
	INFIX	= 'infix';
	IS 		= 'is';
	LET		= 'let';
	MATCH	= 'match';
	MODULE 	= 'module';
	OR		= 'or';
	PREFIX	= 'prefix';
	POSTFIX	= 'postfix';
	REQUIRES= 'requires';
	TYPE 	= 'type';
	VARIANT	= 'variant';
}


@header {
/*
 * Copyright (c) 2009. Simon Johnston. All Rights Reserved.
 * Source file derived from Sol.g
 */
package org.sol.language.parser.grammar;
}

@lexer::header {
/*
 * Copyright (c) 2009. Simon Johnston. All Rights Reserved.
 * Source file derived from Sol.g
 */
package org.sol.language.parser.grammar;
}

/*
 * Parser section *************************************************************
 */

/**
 * The module is the unit for packaging in Sol; it contains types and values.
 */
module
	: 	MODULE qualifiedValueName
		IS!
		documentation?
		( bodyExpression )* 
		END!
		;
	
/**
 * Documentation is available for types, functions using a graph.
 */
documentation
	:	subGraphLiteral
	;
	
/**
 * The legal set of expressions within the body of a module or function.
 */	
bodyExpression
	:  	featureDecl
	|	typeDecl
	|  	variantDecl
	|	functionDecl
	|	operatorDecl
	|	valueDecl
	;		

/**
 * Declaring a value assignment, either to a name or anonymously.
 */	
valueDecl
	:	valueAssignment
	|	anonymousValueAssignment
	;
	
/**
 * The legal set of expressions within the declaration of a type or feature.
 */	
declExpression
	:  	featureDecl
	|	typeDecl
	|  	variantDecl
	|	functionDecl
	|	applyDecl
	|	operatorDecl
	|	memberValueAssignment
	;		

/**
 * General expression yielding a static or computed value.
 */
valueExpression
	:	operatorExpression
	;

/**
 * Value computed using operators
 */	
operatorExpression
	:	chainedSingleExpression 
		( 
			operatorName ( chainedSingleExpression )?
		)?
	|	operatorName chainedSingleExpression
	;

/**
 * One or more calls/operations chaned with a dot.
 */
chainedSingleExpression
	:	( literal | singleExpression ) ( DOT singleExpression )*
	;
	
/**
 * Simple expressions are core literals or function calls.
 */
singleExpression
	:	parenExpression
	|	valueName
	| 	lambdaDecl 
	|	typeConstructor
	|	functionCall
	|	matchExpression
	|	comprehensionExpression
	;

/**
 * A parenthetical expression yielding a computed value.
 */
parenExpression
	:	'(' operatorExpression ')'
	;
	
/**
 * A constant value, either atomic or complex.
 */
literal
	:	simpleLiteral
	|	listLiteral
	|	graphLiteral
	;
	
/**
 * A constant atomic literal value.
 */	
simpleLiteral
	: 	INTLITERAL
	|	HEXLITERAL
	|	BINARYLITERAL
	| 	FLOATLITERAL
	|	CHARLITERAL
	|	STRINGLITERAL
	|	LONGSTRINGLITERAL
	|	URILITERAL1 
	|	URILITERAL2
	;

/**
 * Declaration of a feature structure.
 */	
featureDecl
	: 	FEATURE typeName ( formalTypeArgs )? 
		( EXTENDS typeExtensions )? 
		IS! 
		documentation?
		( declExpression )* 
		END!
	;
		
/**
 * Declaration of a type structure.
 */	
typeDecl
	: 	TYPE typeName ( formalTypeArgs )? 
		( EXTENDS typeExtensions )? 
		IS! 
		documentation?
		(	typeConstructor	
		|	( declExpression )*
		) 
		END!
	;

/**
 * List of types extended by the subject type.
 */	
typeExtensions
	:	typeExtension ( ',' typeExtension )*
	;
	
/**
 * An entry in typeExtensions, a type name followed by formalTypeArgs.
 */
typeExtension
	:	typeName ( formalTypeArgs )?
	;
		
/**
 * Declaration of a variant structure.
 */	
variantDecl
	: 	VARIANT typeName ( formalTypeArgs )? 
		IS! 
		documentation?
		( variantConstructor ( OR variantConstructor )* )?
		( functionDecl | operatorDecl )*
		END!
	;
		
/**
 * Specifier for a variant constructor (optionally parameterized member of a variant).
 */
variantConstructor
	: typeName ( formalParameters )?
	;
	
/**
 * Declaration of a function.
 */	
functionDecl
	: 	FUNCTION functionName 
		( formalTypeArgs )?
		formalParameters
		( typeExpr )?
		functionBody
	;
	
/**
 * Special form of a function, the application form.
 */
applyDecl
	: 	FUNCTION 
		formalParameters
		( typeExpr )?
		functionBody
	;


/**
 * Declaration of a operator.
 */	
operatorDecl
	: 	( 
			(	INFIX operatorName 
				( formalTypeArgs )?
				// use standard formalParameters and a predicate to check length.
				LPAREN formalParameter COMMA! formalParameter RPAREN
			)
		| 	(	PREFIX operatorName
				( formalTypeArgs )?
				LPAREN formalParameter RPAREN
			)
		| 	(	POSTFIX operatorName
				( formalTypeArgs )?
				LPAREN formalParameter RPAREN
			) 
		) 
		( typeExpr )?
		functionBody
	;

/**
 * The body for a function or operator.
 */	
functionBody
	:	IS
		documentation?
		( REQUIRES valueExpression )?
		( ENSURES valueExpression )? 
		( 	(	DO 
				( bodyExpression )+
				END
			)
		|	( 	END		/* deferred */ 
			| 	ABSTRACT 
			) 
		) 
	;
		
/**
 * Declaration of a lambda (function literal) type.
 */
lambdaType
	:	formalParameters
		( typeExpr )?
	;
	
/**
 * Declaration of a lambda (function literal) value.
 */
lambdaDecl
	:	lambdaFormalParameters
		( typeExpr )?
		IS
		DO ( bodyExpression )+ END
	;

/**
 * A comma separated list of parameters within parenthesis.
 */
lambdaFormalParameters
	:	LPAREN! ( lambdaFormalParameter ( ','! lambdaFormalParameter )* )? RPAREN!
	;
	
/**
 * A name, optional type and optional default value.
 */
lambdaFormalParameter
	:	valueName ( typeExpr )?
	;

/**
 * A comma separated list of parameters within parenthesis.
 */
formalParameters
	:	LPAREN! ( formalParameter ( ','! formalParameter )* )? RPAREN!
	;
	
/**
 * A name, optional type and optional default value.
 */
formalParameter
	:	valueName ( typeExpr )?
	|	literal 
	;

/**
 * Assign a value to an identifier.
 */
valueAssignment
	: 	( LET! )? valueName ( typeExpr )? 
		BECOMES! valueExpression
	;		
		
/**
 * Create a feature/type member through value assignment.
 */
memberValueAssignment
	: 	( LET! )? valueName ( typeExpr )? 
		( BECOMES! valueExpression )?
	;		
		
anonymousValueAssignment
	:	BECOMES! valueExpression
	;
	
/**
 * Used to denote the type of a value, a colon followed by a type
 */		
typeExpr
	:	COLON 
		( 	qualifiedTypeName ( formalTypeArgs )?
		|	lambdaType 
		)
	;
	
/**
 * Used to denoted genericity, a comma separated list of type arguments between brakcets.
 */
formalTypeArgs
	:	LBRACKET! 
		( formalTypeArg ( COMMA! formalTypeArg )* )? 
		RBRACKET!
	;
	
/**
 * Denotes a type, with required extension constraint
 */
formalTypeArg
	:	qualifiedTypeName 
		( 	EXTENDS formalTypeArgExtension 
/*
 * Can only define one extension for a type parameter.
 *			( COMMA formalTypeArgExtension )*
 */ 
		)?
	;
	
formalTypeArgExtension
	:	qualifiedTypeName ( formalTypeArgs )?
	;

/**
 * Used to instantiate a generic type.
 */
actualTypeArgs
	:	LBRACKET! 
		( actualTypeArg ( COMMA! actualTypeArg )* )? 
		RBRACKET!
	;
	
/**
 * Denotes a type, with required extension constraint
 */
actualTypeArg
	:	qualifiedTypeName 
	|	qualifiedValueName
	/*
	 * Should be valueExpression
	 */
	;

/**
 * The name of a value, must start with lower case.
 */
valueName
	: 	LC_IDENT
	;
	
qualifiedValueName
	: 	( valueName DOT )* valueName
	;
	
/**
 * The name of a type, must start with upper case.
 */
typeName
	: 	UC_IDENT
	;

/**
 * A qualified type name, perhaps referencing from another module.
 */	
qualifiedTypeName
	:	( valueName DOT )* typeName
	;
	
/**
 * The name of a type, must start with lower case, or be a legal symbol.
 */
functionName
	: 	LC_IDENT 
	;
	
/**
 * The name for an operator, must only select from the symbol set.
 */
operatorName
	:	SY_IDENT
	;
	
/**	
 * Call of a function, with parameters.
 */
functionCall
	:	functionName ( actualTypeArgs )? actualParameters
	;
	
/**
 * Construction of a type value, with parameters.
 */
typeConstructor
	:	typeName ( actualTypeArgs )? ( actualParameters )?
	;
	
/**
 * Actual parameter list provided to a functionCall or typeConstructor.
 */
actualParameters
	:	LPAREN ( actualParameter ( COMMA actualParameter )* )? RPAREN
	;

/**
 * Actual parameters, supporting name assignment.
 */	
actualParameter
	:	( valueName BECOMES )? valueExpression
	;
	
/**
 * List comprehension/For construct.
 */
comprehensionExpression
	:	FOR
			anonymousValueAssignment
			IN valueAssignment ( COMMA valueAssignment )*
			( IF valueExpression )?
		END
	;
	
/**
 * Match is the only builtin control structure in Sol, a pattern-matching 
 * case statement.
 */
matchExpression
	:	MATCH valueExpression
		( patternClause )+
		( elseClause )?
		END
	;

/**
 * A single matching clause in a match statement.
 */	
patternClause
	:	IF patternExpression 
		DO ( bodyExpression )+ END
	;

/**
 * The catch-all clause in a match statement.
 */	
elseClause
	:	ELSE DO ( bodyExpression )+ END
	;

/**
 * A pattern description
 */	
patternExpression
	:	(	typeName ( patternParams )?
		|	functionName patternParams
		|	literal
		)
	;

/**
 * Parameters describing a type/function pattern.
 */	
patternParams
	:	LPAREN
		( 	literalOrVariable ( COMMA! literalOrVariable )* ( COMMA! QMARK2 )?
		|	QMARK2
		)?
		RPAREN
	;

/**
 * A single parameter in a type/function pattern, must be either a literal
 * value or a variable bound to the body of the pattern clause.
 */	
literalOrVariable
	:	literal 
	| 	QMARK valueName
	;
		
/**
 * A constant, List literal value.
 */
listLiteral
	:	LBRACKET valueExpression ( ','! valueExpression )* RBRACKET
	;


/**
 * A constant, Graph literal value.
 */
graphLiteral 
	:	LBRACE statement* RBRACE
	;

/**
 * A constant sub-graph literal value.
 */	
subGraphLiteral 
	:	LBRACKET ( predicates )* RBRACKET
	;

/**
 * An individual statement within a graph.
 */	
statement
	:	subject predicates
	;

/**
 * The subject of a graph statement.
 */	
subject
	:	( URILITERAL1 | URILITERAL2 )
	|	qualifiedValueName
	|	functionCall
	/*
	 * Should be valueExpression
	 */
	;

/**
 * One or more predicate values for a graph statement.
 */	
predicates
	:	predicate objects ( SEMICOLON predicate objects )* DOT
	;

/**
 * A predicate value.
 */	
predicate
	:	( URILITERAL1 | URILITERAL2 )
	|	qualifiedValueName
	|	functionCall
	/*
	 * Should be valueExpression
	 */
	;

/**
 * A list of objects of a graph statement.
 */	
objects
	:	object ( COMMA object )*
	;

/**
 * An object value for a graph statement.
 */	
object
	:	simpleLiteral
	|	subGraphLiteral
//	|	qualifiedValueName
	|	functionCall
	/*
	 * Should be valueExpression
	 */
	;
	
/*
 * Lexer section **************************************************************
 */

/**
 * A comment, should be ignored.
 */
COMMENT 
	options{greedy=false;}
    : '(*' ( . )* '*)' { $channel=HIDDEN; }
    ;

URILITERAL1	
	: 	'<>' 
	;

/**
 * An URI literal, of unbounded length.
 */
URILITERAL2
	:	'<' 
		( ~( ' ' | '<' | '>' | '\t' | '\r' | '\n' ) )*
		'>' 
	;

/**
 * The core becomes, or assignment, operator.
 */    
BECOMES
	: 	'<-'
	;

LPAREN		: '(' ;
RPAREN		: ')' ;
LBRACE		: '{' ;
RBRACE		: '}' ;
LBRACKET	: '[' ;
RBRACKET	: ']' ;
COMMA		: ',' ;
DOT			: '.' ;
COLON		: ':' ;
SEMICOLON	: ';' ;
QMARK		: '?' ;
QMARK2		: '??' ;

/**
 * An identifier that starts with a lower-case character.
 */
LC_IDENT
  	: 	LC_CHARACTER ( UC_CHARACTER | LC_CHARACTER | DIGIT )*
  	;
  
/**
 * An identifier that starts with an upper-case character.
 */
UC_IDENT
  	: 	UC_CHARACTER ( UC_CHARACTER | LC_CHARACTER | DIGIT )*
  	;
  	
/**
 * An identifier containing only symbol characters.
 */
SY_IDENT
	:	SYMBOL+
	;

/**
 * lower case characters (Unicode group 'Lc').
 */  
fragment
LC_CHARACTER
	: 	'a' .. 'z'
	;
	
/**
 * upper case characters (Unicode group 'Lu').
 */  
fragment
UC_CHARACTER
	:	'A' .. 'Z'
	;

fragment
SYMBOL
	: 	'!'  | '@' | '#' | '$' | '%' | '^' | '&' | '*' | '-' | '+' | '=' | '|' 
	| 	'\\' | '/' | '<' | '>' | '~'
	;
	
/**
 * An integer literal, of unbounded length.
 */
INTLITERAL
	:	( SIGN )? ( DIGIT )+
	;

fragment
SIGN
	:	'+' | '-'
	;
	
fragment
DIGIT
	:	'0'..'9'
	;	

/**
 * A hex literal, of unbounded length.
 */
HEXLITERAL
	:	( '0x' | '0X' ) ( DIGIT | 'a'..'f' | 'A'..'F' )+ 
	;	
    
/**
 * A binary literal, of unbounded length.
 */
BINARYLITERAL
	:	( '0b' | '0B' ) ( '0' | '1' )* 
	;	
    
/**
 * A floating-point literal, of unbounded length.
 */    
FLOATLITERAL
	:	( SIGN )? ( DIGIT )+ '.' ( DIGIT )+ 
		( EXPONENT )?
	;   
    
fragment
EXPONENT    
	:	( 'e' | 'E' ) ( SIGN )? ( DIGIT )+ 
	;
    
/**
 * A single character literal.
 */
CHARLITERAL
	:	'\'' 
		(   ESCAPE_CHARACTER 
		|   ~( '\'' | '\\' | '\r' | '\n' )
		) 
		'\''
	; 

/**
 * A string literal, of unbounded length.
 */
STRINGLITERAL
	:	'"' 
		( 	~( '\u0022' | '\u005C' | '\u000A' | '\u000D' ) 
		| 	ESCAPE_CHARACTER 
		)* 
		'"'
	;

LONGSTRINGLITERAL
	:	'"""'
		( . )*
		'"""'
	;

fragment
ESCAPE_CHARACTER 
	: 	'\\' ( 't' | 'b' | 'n' | 'r' | 'f' | '\\' | '"' | '\'' )
	;     

/**
 * Ignorable whitespace.
 */
WHITESPACE 
	:	( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ 
		{ $channel = HIDDEN; } 
  	;